//
//  UIImage+TYZAdd.m
//  DrivieSchoolStudents
//
//  Created by TangBin on 2019/6/4.
//  Copyright © 2019 班文政. All rights reserved.
//

#import "UIImage+TYZAdd.h"
#import <Accelerate/Accelerate.h>
#import <AssetsLibrary/AssetsLibrary.h>
#import <MobileCoreServices/MobileCoreServices.h>

@implementation UIImage (TYZAdd)

static size_t getAssetBytesCallback(void *info, void *buffer, off_t position, size_t count)
{
    ALAssetRepresentation *rep = (__bridge id)info;
    
    NSError *error = nil;
    size_t countRead = [rep getBytes:(uint8_t *)buffer fromOffset:position length:count error:&error];
    if (countRead == 0 && error)
    {
        // We have no way of passing this info back to the caller, so we log it, at least
        debugLog(@"thumbnailForAsset:maxPixelSize: got an error reading an asset: %@", error);
    }
    return countRead;
}

static void releaseAssetCallback(void *info)
{
    CFRelease(info);
}

/// 压缩图片
/// @param asset asset description
/// @param size size description
- (UIImage *)thumbnailForAsset:(ALAsset *)asset maxPixelSize:(NSUInteger)size
{
    NSParameterAssert(asset != nil);
    NSParameterAssert(size > 0);
    
    ALAssetRepresentation *rep = [asset defaultRepresentation];
    
    CGDataProviderDirectCallbacks callbacks = {
      .version=0,
        .getBytePointer = NULL,
        .releaseBytePointer = NULL,
        .getBytesAtPosition = getAssetBytesCallback,
        .releaseInfo = releaseAssetCallback,
    };
    
    CGDataProviderRef provider = CGDataProviderCreateDirect((void *)CFBridgingRetain(rep), [rep size], &callbacks);
    
    CGImageSourceRef source = CGImageSourceCreateWithDataProvider(provider, NULL);
    
    CGImageRef imageDef = CGImageSourceCreateThumbnailAtIndex(source, 0, (__bridge CFDictionaryRef)@{(NSString *)kCGImageSourceCreateThumbnailFromImageAlways:@YES, (NSString *)kCGImageSourceThumbnailMaxPixelSize:[NSNumber numberWithInt:size], (NSString *)kCGImageSourceCreateThumbnailWithTransform:@YES});
    CFRelease(source);
    CFRelease(provider);
    
    if (!imageDef)
    {
        return nil;
    }
    
    UIImage *toReturn = [UIImage imageWithCGImage:imageDef];
    CFRelease(imageDef);
    return toReturn;
}

/**
 设置图片的透明度
 
 @param alpha 0.0~1.0
 @return return value description
 */
- (UIImage *)imageByApplyAlpha:(CGFloat)alpha
{
    UIGraphicsBeginImageContextWithOptions(self.size, NO, 0.0f);
    
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    CGRect area = CGRectMake(0, 0, self.size.width, self.size.height);
    
    CGContextScaleCTM(ctx, 1, -1);
    CGContextTranslateCTM(ctx, 0, -area.size.height);
    
    CGContextSetBlendMode(ctx, kCGBlendModeMultiply);
    
    CGContextSetAlpha(ctx, alpha);
    
    CGContextDrawImage(ctx, area, self.CGImage);
    
    UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
    
    UIGraphicsEndImageContext();
    
    return newImage;
}

- (NSData *)compressWithImage
{
    //进行图像的画面质量压缩
    NSData *data = UIImageJPEGRepresentation(self, 1);
    if (data.length > 100*1024) {
        if (data.length>1024*1024*5)//5M以及以上
        {
            data = UIImageJPEGRepresentation(self, 0.3);
        }
        else if (data.length>1024*1024)//1M-5M
        {
            data = UIImageJPEGRepresentation(self, 0.5);
        }
        else if (data.length>512*1024)//0.5M-1M
        {
            data = UIImageJPEGRepresentation(self, 0.6);
        }
        else if (data.length>200*1024)//0.25M-0.5M
        {
            data = UIImageJPEGRepresentation(self, 0.8);
        }
    }
    debugLog(@"压缩后图片大小为 %.2fK",data.length/1024.0);
    return data;
}

/**
 *  CoreImage图片高斯模糊
 *
 *  @param image 图片
 *  @param blur  模糊数值(默认是10)
 *
 *  @return 重新绘制的新图片
 */

+ (UIImage *)coreBlurImage:(UIImage *)image withBlurNumber:(CGFloat)blur
{
    CIContext *context = [CIContext contextWithOptions:nil];
    CIImage  *inputImage=[CIImage imageWithCGImage:image.CGImage];
    //设置filter
    CIFilter *filter = [CIFilter filterWithName:@"CIGaussianBlur"];
    [filter setValue:inputImage forKey:kCIInputImageKey];
    [filter setValue:@(blur) forKey: @"inputRadius"];
    //模糊图片
    CIImage *result=[filter valueForKey:kCIOutputImageKey];
    CGImageRef outImage=[context createCGImage:result fromRect:[result extent]];
    UIImage *blurImage=[UIImage imageWithCGImage:outImage];
    CGImageRelease(outImage);
    return blurImage;
}
/**
 *  vImage模糊图片
 *
 *  @param image 原始图片
 *  @param blur  模糊数值(0-1)
 *
 *  @return 重新绘制的新图片
 */
+ (UIImage *)boxblurImage:(UIImage *)image withBlurNumber:(CGFloat)blur
{
    if (blur < 0.f || blur > 1.f) {
        blur = 0.5f;
    }
    int boxSize = (int)(blur * 40);
    boxSize = boxSize - (boxSize % 2) + 1;
    
    CGImageRef img = image.CGImage;
    
    vImage_Buffer inBuffer, outBuffer;
    vImage_Error error;
    
    void *pixelBuffer;
    //从CGImage中获取数据
    CGDataProviderRef inProvider = CGImageGetDataProvider(img);
    CFDataRef inBitmapData = CGDataProviderCopyData(inProvider);
    //设置从CGImage获取对象的属性
    inBuffer.width = CGImageGetWidth(img);
    inBuffer.height = CGImageGetHeight(img);
    inBuffer.rowBytes = CGImageGetBytesPerRow(img);
    
    inBuffer.data = (void*)CFDataGetBytePtr(inBitmapData);
    
    pixelBuffer = malloc(CGImageGetBytesPerRow(img) *
                         CGImageGetHeight(img));
    
    if(pixelBuffer == NULL)
        NSLog(@"No pixelbuffer");
    
    outBuffer.data = pixelBuffer;
    outBuffer.width = CGImageGetWidth(img);
    outBuffer.height = CGImageGetHeight(img);
    outBuffer.rowBytes = CGImageGetBytesPerRow(img);
    
    error = vImageBoxConvolve_ARGB8888(&inBuffer, &outBuffer, NULL, 0, 0, boxSize, boxSize, NULL, kvImageEdgeExtend);
    
    if (error) {
        NSLog(@"error from convolution %ld", error);
    }
    
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    CGContextRef ctx = CGBitmapContextCreate(
                                             outBuffer.data,
                                             outBuffer.width,
                                             outBuffer.height,
                                             8,
                                             outBuffer.rowBytes,
                                             colorSpace,
                                             kCGImageAlphaNoneSkipLast);
    CGImageRef imageRef = CGBitmapContextCreateImage (ctx);
    UIImage *returnImage = [UIImage imageWithCGImage:imageRef];
    
    //clean up
    CGContextRelease(ctx);
    CGColorSpaceRelease(colorSpace);
    
    free(pixelBuffer);
    CFRelease(inBitmapData);
    
//    CGColorSpaceRelease(colorSpace);
    CGImageRelease(imageRef);
    
    return returnImage;
}

+ (UIImage *)imageWithImage:(UIImage *)image scaledToSize:(CGSize)newSize
{
    UIGraphicsBeginImageContext(newSize);
    [image drawInRect:CGRectMake(0, 0, newSize.width, newSize.height)];
    UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return newImage;
}

+ (UIImage *)compressImageQuality:(UIImage *)image toByte:(NSInteger)maxLength
{
    CGFloat compression = 1;
    NSData *data = UIImageJPEGRepresentation(image, compression);
    if (data.length < maxLength) return image;
    CGFloat max = 1;
    CGFloat min = 0;
    for (int i = 0; i < 6; ++i)
    {
        compression = (max + min) / 2;
        data = UIImageJPEGRepresentation(image, compression);
        if (data.length < maxLength * 0.9) {
            min = compression;
        } else if (data.length > maxLength) {
            max = compression;
        } else {
            break;
        }
    }
    UIImage *resultImage = [UIImage imageWithData:data];
    return resultImage;
}

/// 压缩图片 先质量压缩，后大小压缩
/// @param image image description
/// @param maxLength maxLength description
+ (void)compressImage:(UIImage *)image toByte:(NSInteger)maxLength completion:(void(^)(UIImage *image, NSData *data, CGFloat compression))completion
{
    CGFloat compression = 1.0;
    NSData *data = UIImageJPEGRepresentation(image, compression);
    debugLog(@"原图大小=%.2f kb", data.length / 1024.0);
    if (data.length < maxLength)
    {
        if (completion)
        {
            completion(image, data, compression);
        }
        return;
//        return @{@"image":image, @"compression":@(compression)};
    }
    
    CGFloat max = 1;
    CGFloat min = 0;
    compression = pow(2, -6); // 植树二分处理，首先计算最小值
    debugLog(@"compression=%.2f", compression);
    data = UIImageJPEGRepresentation(image, compression);
    
    if (data.length < maxLength)
    {
        for (int i=0; i<6; ++i)
        {
            compression = (max + min) / 2;
            data = UIImageJPEGRepresentation(image, compression);
            // 容错区间范围 0.9 ~ 1.0
            if (data.length < maxLength * 0.9)
            {
                min = compression;
            }
            else if (data.length > maxLength)
            {
                max = compression;
            }
            else
            {
                break;
            }
        }
    }
    
    
    UIImage *resultImage = [UIImage imageWithData:data];
    if (data.length < maxLength)
    {
        debugLog(@"清晰度压缩后图大小=%.2f kb", data.length / 1024.0);
        if (completion)
        {
            completion(resultImage, data, compression);
        }
        return;
//        return @{@"image":resultImage, @"compression":@(compression)};
    }
    
    // compress by size
    /*NSUInteger lastDataLength = 0;
    while (data.length > maxLength && data.length != lastDataLength)
    {
        lastDataLength = data.length;
        CGFloat ratio = (CGFloat)maxLength / data.length;
        CGSize size = CGSizeMake((NSUInteger)(resultImage.size.width * sqrtf(ratio)),
                                 (NSUInteger)(resultImage.size.height * sqrtf(ratio))); // Use NSUInteger to prevent white blank
        UIGraphicsBeginImageContext(size);
        [resultImage drawInRect:CGRectMake(0, 0, size.width, size.height)];
        resultImage = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
        data = UIImageJPEGRepresentation(resultImage, compression);
    }
    */
    while (data.length > maxLength)
    {
        @autoreleasepool {
            CGFloat ratio = (CGFloat)maxLength / data.length;
            CGSize size = CGSizeMake((NSUInteger)(resultImage.size.width * sqrtf(ratio)),
                                                 (NSUInteger)(resultImage.size.height * sqrtf(ratio)));
            resultImage = [self thumbnailForData:data maxPixelSize:MAX(size.width, size.height)];
            data = UIImageJPEGRepresentation(resultImage, compression);
        }
    }
    debugLog(@"尺寸压缩后图大小=%.2f kb", data.length / 1024.0);
    if (completion)
    {
        completion(resultImage, data, compression);
    }
//    return @{@"image":resultImage, @"compression":@(compression)};
    return;
}

+ (UIImage *)thumbnailForData:(NSData *)data maxPixelSize:(NSUInteger)size
{
    CGDataProviderRef provider = CGDataProviderCreateWithCFData((__bridge CFDataRef)data);
    CGImageSourceRef source = CGImageSourceCreateWithDataProvider(provider, NULL);
    
    NSDictionary *param = @{
        (NSString *)kCGImageSourceCreateThumbnailFromImageAlways : @YES,
        (NSString *)kCGImageSourceThumbnailMaxPixelSize : @(size),
        (NSString *)kCGImageSourceCreateThumbnailWithTransform : @YES,
    };
    CGImageRef imageRef = CGImageSourceCreateThumbnailAtIndex(source, 0, (__bridge CFDictionaryRef)param);
    
    CFRelease(source);
    CFRelease(provider);
    if (!imageRef)
    {
        return nil;
    }
    
    UIImage *toReturn = [UIImage imageWithCGImage:imageRef];
    CFRelease(imageRef);
    return toReturn;
}

@end
























